package destiny.预测;

import java.util.HashMap;
import java.util.Map;

import destiny.common.阴阳;
import destiny.干.十神;
import destiny.干.天干;
import destiny.干.生旺死绝;
import destiny.支.地支;

public class 格局 {

	/**
	 * 八字用神，专凭月令。月无用神，始寻外格。月令，本也，外格，末也。
	 * 
	 * 所谓月令无用者，原是月令本无用神。以财被劫、官被伤之类，用神已破，若无救应即为破格，无需弃之以就外格。
	 * 
	 * 杂格者，月令无用，取外格而用之。其格甚多，故谓之杂。大约要干头无官无煞，方成外格。如有官煞，则自有官煞为用，无劳外格矣。若逢财尚可取格，然财根深，
	 * 或财透两位，则亦以财为重，不取外格也。
	 * 
	 * 胡子：此处取喜用神力大者。月令初始权重甚大，故月令者常为主格。以阴阳五行论事故，此处杂格正格皆以十神用神论
	 */
	private static 十神 定十神格(四柱排盘 pan) {
		十神 神 = null;
		int max = 0;
		int maxWeight = 0;
		for (int i = 0; i < pan.柱数().length; ++i) {
			if (i != pan.日序) {
				干数 shu = pan.柱数()[i].干数();
				if (shu.用神权重() > max) {
					神 = shu.神();
					max = shu.用神权重();
					maxWeight = shu.getWeight();
				} else if (shu.用神权重() == max && shu.getWeight() > maxWeight) {
					神 = shu.神();
					maxWeight = shu.getWeight();
				}
			}

			for (干数 shu : pan.柱数()[i].支数().藏干数()) {
				if (shu.用神权重() > max) {
					神 = shu.神();
					max = shu.用神权重();
					maxWeight = shu.getWeight();
				} else if (shu.用神权重() == max && shu.getWeight() > maxWeight) {
					神 = shu.神();
					maxWeight = shu.getWeight();
				}
			}
		}
		if (max > 0)
			return 神;

		return null;
	}

	/**
	 * 正格定格局法 ：
	 * 
	 * 1. 以月支主气透天干者为格（透天干者，如戌之藏干为戊,辛,丁，在年干,月干或时干见戊），日元为癸，故成正官格。
	 * 
	 * 2. 月支主气不透，则以余气透干为格.。（例：午之藏干为丁,己，天干不见丁，但见己，日元是辛，故为偏印格）
	 * 
	 * 3. 月支主气不透，则以余气透干为格；如有两个余气透干，以气势较强之一个为格。
	 * 
	 * 4. 月支只有主气无余气，虽然并不透天，仍可为格。
	 * 
	 * 5. 月支中主气余气也不透天，当然主气最强，就以主气为格。
	 * 
	 * 胡子：透干已有五行加权，取最大权值即可。
	 */
	private static 十神 定十神格0(四柱排盘 pan) {
		干数[] 月提藏干 = pan.柱数()[pan.月序].支数().藏干数();

		十神 神 = null;
		int maxWeight = 0;
		for (干数 shu : 月提藏干) {
			if (shu.getWeight() > maxWeight) {
				神 = shu.神();
				maxWeight = shu.getWeight();
			}
		}
		return 神;
	}

	/**
	 * 胡子：五行加权，取最大权值即可。
	 */
	private static 十神 定十神格1(四柱排盘 pan) {
		Map<十神, Integer> map = new HashMap<十神, Integer>();
		十神 神 = null;
		int maxWeight = 0, w;
		for (int i = pan.柱数().length - 1; i >= 0; --i) {
			干支数 gzs = pan.柱数()[i];
			for (干数 shu : gzs.支数().藏干数()) {
				神 = shu.神();
				w = 0;
				if (map.containsKey(神)) {
					w = map.get(神);
				}
				w += shu.getWeight();
				map.put(神, w);
			}

			if (i == pan.日序)
				continue;
			干数 shu = gzs.干数();
			神 = shu.神();
			w = 0;
			if (map.containsKey(神)) {
				w = map.get(神);
			}
			w += shu.getWeight();
			map.put(神, w);
		}

		for (十神 s : map.keySet()) {
			w = map.get(s);
			if (w > maxWeight) {
				神 = s;
				maxWeight = w;
			}
		}
		return 神;
	}

	public static 格局 求格局(四柱排盘 pan) {
		天干 日主 = pan.柱数()[pan.日序].干数().天干();
		地支 月令 = pan.柱数()[pan.月序].支数().地支(), 建禄 = 生旺死绝.寻支(日主, 生旺死绝.临官), 刃劫 = 生旺死绝
				.寻支(日主, 生旺死绝.帝旺);
		格 取格 = null;
		/*
		 * 月令逢禄为建禄，日支坐禄为专禄，时支逢禄为归禄。月劫者月令逢劫也，阳干为刃，阴干为劫。建禄月劫，皆无取以为用之法，另取财官煞食用神，
		 * 则与财官煞食看法无二。故以用神分类者，无另立之必要也。
		 */
		if (阴阳.阳.equals(日主.术数().阴阳()) && 月令.equals(刃劫)) {
			取格 = 格.阳刃格;
		} else if (月令.equals(建禄) || 月令.equals(刃劫)) {
			取格 = 格.建禄月劫格;
		}

		if (取格 == null)
			取格 = 格.杂格;

		十神 十神格 = 定十神格1(pan);
		// 十神 十神格 = 定十神格(pan);
		// if (十神格 == null) {
		// 十神格 = 定十神格0(pan);
		// return new 格局(取格, 十神格);
		// }
		if (取格 == null) {
			if (十神.正官.equals(十神格)) {
				取格 = 格.正官格;
			} else if (十神.正官.equals(十神格)) {
				取格 = 格.正官格;
			} else if (十神.七杀.equals(十神格)) {
				取格 = 格.偏官格;
			} else if (十神.食神.equals(十神格)) {
				取格 = 格.食神格;
			} else if (十神.伤官.equals(十神格)) {
				取格 = 格.伤官格;
			} else if (十神.正财.equals(十神格) || 十神.偏财.equals(十神格)) {
				取格 = 格.财格;
			} else if (十神.正印.equals(十神格) || 十神.偏印.equals(十神格)) {
				取格 = 格.印绶格;
			}
		}

		return new 格局(取格, 十神格);
	}

	private 格 取格;
	private 十神 十神格;

	public 格局(格 取格, 十神 十神格) {
		this.取格 = 取格;
		this.十神格 = 十神格;
	}

	public 格 取格() {
		return 取格;
	}

	public 十神 十神格() {
		return 十神格;
	}
}
